package services

import (
	"fmt"
	"strconv"
	"time"

	"cashew.com/cashew_common/utils"
	"cashew.com/cashew_match/models"
	"github.com/beego/beego/v2/core/logs"
)

const (
	// Redis中存储用户信息的Hash Key的前缀
	UserCachePrefix = "CASHEW::USERCACHE::"
	// 用户信息在Redis中的缓存时间，单位为秒，这里设置为7天，7 * 24 * 60 * 60 = 604800
	UserCacheExpiration = 604800
)

type UserCache struct {
	UserId      int64  `json:"user_id"`
	Gender      int    `json:"gender"`
	SubRegionId int    `json:"sub_region_id"`
	Nick        string `json:"nick"`
	HeadImg     string `json:"head_img"`
	Age         int    `json:"age"`
	FlagImage   string `json:"flag_image"`
}

// SecondsToDuration 将代表秒数的int值转换为time.Duration类型
func SecondsToDuration(seconds int) time.Duration {
	return time.Duration(seconds) * time.Second
}

// StoreUserInfoToRedis 将用户信息存入Redis，并设置缓存时间为7天
func StoreUserInfoToRedis(redisserver *utils.RedisService, userId string, userInfo *UserCache) error {
	key := UserCachePrefix + userId

	// 使用pipeline减少网络往返次数，提高效率
	pipe := redisserver.GetPipeline()
	defer pipe.Close()

	// 将UserCache结构体转换为Redis命令并添加到pipeline中
	numUserId, _ := strconv.ParseInt(userId, 10, 64)
	pipe.HSet(key, "user_id", numUserId)
	pipe.HSet(key, "gender", strconv.Itoa(userInfo.Gender))
	pipe.HSet(key, "sub_region_id", strconv.Itoa(userInfo.SubRegionId))
	pipe.HSet(key, "nick", userInfo.Nick)
	pipe.HSet(key, "head_img", userInfo.HeadImg)
	pipe.HSet(key, "age", strconv.Itoa(userInfo.Age))
	pipe.HSet(key, "flag_image", GetPathFromURL(userInfo.FlagImage))

	// 设置过期时间
	duration := SecondsToDuration(UserCacheExpiration)
	pipe.Expire(key, duration)

	// 执行pipeline中的所有命令
	_, err := pipe.Exec()
	if err != nil {
		return fmt.Errorf("存储用户信息到Redis失败: %v", err)
	}
	logs.Debug("StoreUserInfoToRedis: 成功存储用户信息到Redis")

	return nil
}

// GetUserInfoFromRedis 从Redis获取用户信息，并转换为UserCache结构体返回，如果不存在则根据identity判断查询数据库并更新缓存
func GetUserInfoFromRedis(redisserver *utils.RedisService, userId string, identity int) (userInfo *UserCache, err error) {
	key := UserCachePrefix + userId

	result, err := redisserver.HGetAll(key)
	if err != nil {
		// 处理Redis操作错误
		return nil, fmt.Errorf("从Redis获取用户信息失败: %v", err)
	}
	logs.Debug("GetUserInfoFromRedis: key=%s, result=%v", key, result)

	if len(result) > 5 {
		numUserId, err := strconv.ParseInt(result["user_id"], 10, 64)
		if err != nil {
			return nil, fmt.Errorf("转换user_id字段失败: %v", err)
		}
		gender, err := strconv.Atoi(result["gender"])
		if err != nil {
			return nil, fmt.Errorf("转换gender字段失败: %v", err)
		}
		subRegionId, err := strconv.Atoi(result["sub_region_id"])
		if err != nil {
			return nil, fmt.Errorf("转换sub_region_id字段失败: %v", err)
		}
		age, err := strconv.Atoi(result["age"])
		if err != nil {
			return nil, fmt.Errorf("转换age字段失败: %v", err)
		}
		userInfo = &UserCache{
			UserId:      numUserId,
			Gender:      gender,
			SubRegionId: subRegionId,
			Nick:        result["nick"],
			HeadImg:     result["head_img"],
			Age:         age,
			FlagImage:   CompleteURL(result["flag_image"]),
		}

		// 如果缓存中没有flag_image字段，则从数据库中获取并更新缓存
		if userInfo.FlagImage == "" {
			subRegionInfo, err := models.GetSub_region_configurationByRegionId(subRegionId)
			if err != nil {
				return nil, fmt.Errorf("从数据库获取subRegionInfo失败: %v", err)
			}
			userInfo.FlagImage = subRegionInfo.FlagImage
			// 更新缓存中的flag_image字段
			if err := UpdateUserCacheFields(redisserver, userId, map[string]interface{}{"flag_image": userInfo.FlagImage}); err != nil {
				return nil, fmt.Errorf("更新用户缓存字段信息失败: %v", err)
			}
		}
		return userInfo, nil
	}

	// 缓存中未找到数据，根据identity判断查询数据库并封装获取用户信息的逻辑
	if userInfo, err = fetchUserInfoFromDB(identity, userId); err != nil {
		return nil, err
	}

	// 将从数据库获取到的用户信息存入Redis缓存
	if err = StoreUserInfoToRedis(redisserver, userId, userInfo); err != nil {
		return nil, fmt.Errorf("存储用户信息到Redis失败: %v", err)
	}

	return userInfo, nil
}

// 封装从数据库获取用户信息的逻辑，减少代码冗余
func fetchUserInfoFromDB(identity int, userId string) (userInfo *UserCache, err error) {
	numUserId, err := strconv.ParseInt(userId, 10, 64)
	if err != nil {
		return nil, fmt.Errorf("用户ID转换失败: %v", err)
	}

	if identity == 1 {
		viewerInfo, err := models.GetUsersByUserId(numUserId)
		if err != nil {
			return nil, fmt.Errorf("从数据库获取viewerInfo失败: %v", err)
		}
		userInfo = fromViewerInfo(viewerInfo)
	} else {
		anchorInfo, err := models.GetAnchor_infoByAnchorId(numUserId)
		if err != nil {
			return nil, fmt.Errorf("从数据库获取anchorInfo失败: %v", err)
		}
		userInfo = fromAnchorInfo(anchorInfo)
	}

	// 查询对应的国旗信息并更新
	subRegionInfo, err := models.GetSub_region_configurationByRegionId(userInfo.SubRegionId)
	if err != nil {
		return nil, fmt.Errorf("获取国旗信息失败: %v", err)
	}
	userInfo.FlagImage = subRegionInfo.FlagImage

	return userInfo, nil
}

func fromViewerInfo(viewerInfo *models.Users) (userInfo *UserCache) {
	return &UserCache{
		UserId:      viewerInfo.UserId,
		Gender:      viewerInfo.Gender,
		SubRegionId: viewerInfo.SubRegionId,
		Nick:        viewerInfo.Nick,
		HeadImg:     viewerInfo.HeadImg,
		Age:         viewerInfo.Age,
	}
}

func fromAnchorInfo(anchorInfo *models.Anchor_info) (userInfo *UserCache) {
	return &UserCache{
		UserId:      anchorInfo.AnchorId,
		Gender:      anchorInfo.Gender,
		SubRegionId: anchorInfo.SubRegionId,
		Nick:        anchorInfo.Nick,
		HeadImg:     anchorInfo.HeadImg,
		Age:         anchorInfo.Age,
	}
}

// UpdateUserCacheFields 更新用户缓存中指定的字段信息
func UpdateUserCacheFields(redisserver *utils.RedisService, userId string, updateFields map[string]interface{}) error {
	key := UserCachePrefix + userId

	pipe := redisserver.GetPipeline()
	defer pipe.Close()

	for field, value := range updateFields {
		var strValue string
		switch field {
		case "gender", "sub_region_id", "age":
			if intValue, ok := value.(int); ok {
				strValue = strconv.Itoa(intValue)
			} else {
				return fmt.Errorf("字段 '%s' 的值不是整数类型", field)
			}
		case "nick", "head_img", "flag_image":
			if strValue, ok := value.(string); ok {
				strValue = strValue // 直接使用
			} else {
				return fmt.Errorf("字段 '%s' 的值不是字符串类型", field)
			}
		default:
			return fmt.Errorf("不支持更新的字段: %v", field)
		}
		// 使用Hset更新对应字段，而不是删除整个key再重建
		pipe.HSet(key, field, strValue)
	}

	_, err := pipe.Exec()
	if err != nil {
		return fmt.Errorf("更新用户缓存字段信息失败: %v", err)
	}

	return nil
}
